package com.upcontrol.uartagent.core;

import com.csjbot.csjbase.log.Csjlogger;
import com.csjbot.snowbot_rogue.Events.HWTestEvent;
import com.csjbot.snowbot_rogue.utils.NetDataTypeTransform;
import com.upcontrol.uartagent.core.inter.DataReceive;
import com.upcontrol.uartagent.core.inter.IConnector;
import com.upcontrol.uartagent.core.util.Error;

import org.greenrobot.eventbus.EventBus;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Arrays;

import android_serialport_api.SerialPort;

/**
 * Copyright (c) 2017, SuZhou CsjBot. All Rights Reserved.
 * www.csjbot.com
 * <p>
 * Created by 浦耀宗 at 2017/02/09 0009-14:06.
 * Email: puyz@csjbot.com
 */

public class UartConnectRK3288 implements IConnector {
    private SerialPort mSerialPort = null;

    protected OutputStream mOutputStream;
    private InputStream mInputStream;
    private ReadThread mReadThread;
    private DataReceive uartDataReceive;
    private boolean isRunning;
    private static final byte HEADER = (byte) 0xAA;
    private static final int BUFFER_READ_SIZE = 1;
    private static final int CONTENT_WITHOUT_DATA = 6;

    private class ReadThread extends Thread {

        @Override
        public void run() {
            super.run();
            Csjlogger.info("start 上身板接收线程");
            while (isRunning) {
                int size = 0;
                try {
                    byte[] buffer = new byte[BUFFER_READ_SIZE];

                    if (mInputStream == null) {
                        Csjlogger.error("mInputStream == null");
                        return;
                    }

                    size = mInputStream.read(buffer);
                    if (size > 0) {
//                        onDataReceived(buffer, size);
                        Csjlogger.info("UartConnectRK3288 {}", NetDataTypeTransform.dumpHex(buffer));
                        strickBuffer(buffer, size);
//                        EventBus.getDefault().post(new HWTestEvent(0, NetDataTypeTransform.dumpHex(buffer)));
                    }
                } catch (IOException e) {
                    Csjlogger.error(e);
                    return;
                }
            }
        }
    }

    // 256的缓存
    private byte[] mBuffer = new byte[256];
    private int offset = 0;

    private synchronized void strickBuffer(byte buf[], int size) {
        System.arraycopy(buf, 0, mBuffer, offset, size);
        offset += size;
        if (offset < mBuffer.length) {
            checkBuffer();
        } else {
            Arrays.fill(mBuffer, (byte) 0);
            offset = 0;
        }
    }

    private synchronized void checkBuffer() {
        // mbugger里面永远只放一个合法的包
        if (mBuffer[0] == HEADER) {
            // 6是最小的一个包
            if (offset >= CONTENT_WITHOUT_DATA) {
                int len = mBuffer[4];

                if (len < 0) {
                    Arrays.fill(mBuffer, (byte) 0);
                    offset = 0;
                    return;
                }

                // 读到了一个完整的包
                if (offset == len + CONTENT_WITHOUT_DATA) {
                    Csjlogger.info("收到上身板发送的原始数据 {}", NetDataTypeTransform.dumpHex(Arrays.copyOf(mBuffer, offset)));
                    onDataReceived(mBuffer, offset);
                    Arrays.fill(mBuffer, (byte) 0);
                    offset = 0;
                }
            }

        } else {
            // 如果头不是的话就舍弃，从头再来
            Arrays.fill(mBuffer, (byte) 0);
            offset = 0;
        }
    }

    private void onDataReceived(byte[] buffer, int size) {
        if (uartDataReceive != null) {
            uartDataReceive.onReceive(Arrays.copyOf(buffer, size));
        }
    }

    @Override
    public int connect(String hostName, int port) {
        int ret = 0;
        try {
            mSerialPort = new SerialPort(new File(hostName), port, 0, "上身控制");
            mOutputStream = mSerialPort.getOutputStream();
            mInputStream = mSerialPort.getInputStream();
            isRunning = true;
            /* Create a receiving thread */
            Csjlogger.debug("=========连接成功=====================================================");
            mReadThread = new ReadThread();
            mReadThread.start();
        } catch (SecurityException e) {
            Csjlogger.error("SecurityException", e);
            ret = Error.Uart.CONNECT_SECURITY_EXCEPTION;
        } catch (IOException e) {
            Csjlogger.error("IOException", e);
            ret = Error.Uart.CONNECT_IO_ERROR;
        }

        return ret;
    }

    @Override
    public int sendData(byte[] data) {
        int ret = Error.Uart.SEND_SUCCESS;
        if (mOutputStream != null) {
            try {
                mOutputStream.write(data);
                Csjlogger.debug("向上身板发送数据 {} ", NetDataTypeTransform.dumpHex(data));
                EventBus.getDefault().post(new HWTestEvent("向上身板发送数据 " + NetDataTypeTransform.dumpHex(data)));
            } catch (IOException e) {
                Csjlogger.error("IOException", e);
                ret = Error.Uart.SEND_IO_ERROR;
            }
        } else {
            Csjlogger.error("mOutputStream == null");
            ret = Error.Uart.SEND_OUT_STREAM_NULL;
        }

        return ret;
    }

    @Override
    public void setDataReceive(DataReceive receive) {
        uartDataReceive = receive;
    }

    @Override
    public boolean isRunning() {
        return isRunning;
    }

    @Override
    public void destroy() {
        if (mSerialPort != null) {
            Csjlogger.info("destroy");
            mSerialPort = null;
            mReadThread.interrupt();
            isRunning = false;
        }
    }
}
